#!/usr/bin/python
# -*- coding: utf-8 -*-
import omen.tools.configuration as omconf
import omen.connectors.mail as ommail
import omen.tools.omen_tools as omtool
import omen.engine.core.daemon as omenproc
import time
import omen.connectors.mongodb as omenmongo
import email

class MessageState(object):
    INCOMING = 'INCOMING'
    COMPUTING = 'COMPUTING'
    
class InComingMsg(object):
    MESSAGE_ID = "message_id"
    INBOX_ID = "inbox_id"
    SUBJECT = "subject"
    STATE = "state"
    
class TimeSlice(object):
    STANDARD = 5
    EXCEPTION = 10
    
def get_mail_client(conf):
    # create omenmail client
    # check if all parameters are present ?
    mail_client = ommail.MailClient(conf["mail_connector.host"], 
                                    conf["mail_connector.port"], 
                                    omtool.ParseTools.str_to_boolean(conf["mail_connector.ssl"]))
    # connect to mailbox
    mail_client.open(conf["mail_connector.user"], conf["mail_connector.password"])
    mail_client.select()
    return mail_client

# method to get message from the mailbox
def get_messages(configuration):
    while True:
        try:
            # get a omenmail client
            mail_client = get_mail_client(configuration)
            
            # connect to database
            mongo_client = omenmongo.SafeMongoClient()
            database = mongo_client['test_mail']
            in_message_collection = database['in_messages']
            
            while True:
                try:
                    #treatment ...
                   
                    # get messages
                    message_count, messages = mail_client.get_unanswered_messages(configuration["mail_connector.max_message"], True)
                    # save it to database
                    for message in messages:
                        msg_id_in_box, msg_string = message
                        obj_message = email.message_from_string(msg_string)
                        # save in-coming message in database
                        d_message = {InComingMsg.MESSAGE_ID: obj_message["MESSAGE-ID"].strip(), 
                                     InComingMsg.INBOX_ID: msg_id_in_box, 
                                     InComingMsg.SUBJECT: obj_message["SUBJECT"], 
                                     InComingMsg.STATE: MessageState.INCOMING}
                        in_message_collection.insert(d_message)
                        # mark message as answered
                        mail_client.mark_message_as_answered(msg_id_in_box)
                    if not message_count:
                        time.sleep(TimeSlice.STANDARD)
                except Exception, err:
                    # exception ...
                    print str(err)
                    time.sleep(TimeSlice.EXCEPTION)
            try:
                if mail_client:
                    mail_client.close()
            except:
                pass
            try:
                if mongo_client:
                    mongo_client.close()
            except:
                pass
            
        except Exception, err:
            print str(err)
            time.sleep(TimeSlice.EXCEPTION)

# From the input message
# . get body and subject of the message and put it to database
# . generate a mail notification message and save it to database
#     . put a shortcut  
def sample_message_treatement(configuration):
    #TODO: create a notification message
    pass

# main message treatment routine: just get one message to treat from database, get full message from mail_box ...
# ... and call the treatment 
def treat_messages(configuration):
    while True:
        try:
            # get a omenmail client
            mail_client = get_mail_client(configuration)
            
            # connect to database
            mongo_client = omenmongo.SafeMongoClient()
            database = mongo_client['test_mail']
            in_message_collection = database['in_messages']
            while True:
                try:
                    # get a message in INCOMING state and change the state to COMPUTING
                    in_message = in_message_collection.find_and_modify(query={InComingMsg.STATE: MessageState.INCOMING}, update={"$set": {InComingMsg.STATE: MessageState.COMPUTING}}, new=True)
                    if in_message:
                        # get full message from database
                        message = mail_client.get_message_by_id(in_message[InComingMsg.INBOX_ID])
                        obj_message = email.message_from_string(message)
                        print(obj_message["MESSAGE-ID"])
                    else:
                        time.sleep(TimeSlice.STANDARD)
                except Exception, err:
                    # exception ...
                    print str(err)
                    time.sleep(TimeSlice.EXCEPTION)
            
            try:
                if mail_client:
                    mail_client.close()
            except:
                pass
            try:
                if mongo_client:
                    mongo_client.close()
            except:
                pass
            
        except Exception, err:
            print str(err)
            time.sleep(TimeSlice.EXCEPTION)
            
# send messages:
# . get message to send from database
# . send it using a smtp connector          
def send_messages(configuration):
    pass

def main():
    running = True
    type_process = omenproc.DaemonType.PROCESS
    list_process = []
    try:
        #get configuration file in a pretty format
        pretty_conf = omconf.JSONConf.parse_to_pretty(omconf.JSONConf.load_from_file('conf/appli.conf'))
        
        # create a child process to get the messages
        get_message_treatment_process = omenproc.DaemonFactory.get_daemon("get_messages_daemon", get_messages, (pretty_conf,), type_process)
        list_process.append(get_message_treatment_process)
        get_message_treatment_process.start()
        
        # create child processes to treat the messages        
        for i in range(3):
            treat_messages_process = omenproc.DaemonFactory.get_daemon("treat_message_daemon%s" % (str(i)), treat_messages, (pretty_conf,), type_process)
            list_process.append(treat_messages_process)
            treat_messages_process.start()
        
        # create a pool to send the result messages
        send_process = omenproc.DaemonFactory.get_daemon("send_messages_daemon", send_messages, (pretty_conf,), type_process)
        list_process.append(send_process)
        send_process.start() 
        
        try:
            while running:
                # add code to check the other processes
                time.sleep(10)
        except (KeyboardInterrupt, SystemExit):
            running = False
            print('Stop request received !')
        except Exception, err:
            print('Unexpected exception: %s' % str(err))
            
    except Exception, err:
        print('Exception: %s' % (str(err)))
        
    finally:
        for proc in list_process:
            proc.terminate()
        for proc in list_process:
            proc.join()
            
    print('End ! End ! End !')

if __name__ == '__main__':
    main()
        